<template>
  <div class="person">
    <h1>情况一：监视【ref】定义的【基本类型】数据</h1>
    <h2>当前求和为：{{ sum }}</h2>
    <button @click="changeSum">点我 sum + 1</button>
  </div>

  <div class="person">
    <h1>情况二：监视【ref】定义的【对象类型】数据</h1>
    <h2>当前姓名：{{ person.name }}，年龄：{{ person.age }}</h2>
    <button @click="changeName">修改名字</button>
    <button @click="changeAge">修改年龄</button>
    <button @click="changePerson">修改整个人</button>
  </div>

  <div class="person">
    <h1>情况三：监视【reactive】定义的【对象类型】数据</h1>
    <h2>当前姓名：{{ person1.name }}，年龄：{{ person1.age }}</h2>
    <button @click="changeName1">修改名字</button>
    <button @click="changeAge1">修改年龄</button>
    <button @click="changePerson1">修改整个人</button>
  </div>
</template>

<script setup lang="ts" name="Person4">
import {reactive, ref, watch} from 'vue';

// 情况一：监视【ref】定义的【基本类型】数据
/**
 * 数据
 */
const sum = ref<number>(0);

/**
 * 方法
 */
const changeSum = (): void => {
  sum.value++;
};

/**
 * 监听
 * 第一个参数是要监听的数据
 * 第二个参数是监听到数据变化后的回调函数
 */
const stopWatch = watch(sum, (newValue, oldValue) => {
  console.log('sum发生了变化', newValue, oldValue);
  if (newValue > 5) {
    console.log('sum大于5了，停止监听');
    stopWatch();
  }
});

// 情况二：监视【ref】定义的【对象类型】数据
/**
 * 数据
 */
const person = ref<{ name: string, age: number }>({name: '张三', age: 18});

/**
 * 方法
 */
const changeName = (): void => {
  person.value.name += '~';
};

const changeAge = (): void => {
  person.value.age++;
};

const changePerson = (): void => {
  person.value = {name: '李四', age: 20};
};
/**
 * 监听
 * 情况一：监视【ref】定义的【对象类型】数据，监视的是对象的引用地址，而不是对象的属性
 * 情况二：监视【ref】定义的【对象类型】数据，监视的是对象的属性
 * immediate: true 表示立即执行回调函数，否则只有在数据发生变化时才会执行回调函数
 * deep: true 表示深度监视，即对象内部的属性发生变化也会触发回调函数
 * 监视`ref`定义的【对象类型】数据：直接写数据名，监视的是对象的【地址值】，若想监视对象内部的数据，要手动开启深度监视。
 *
 * 注意：
 *
 * 若修改的是`ref`定义的对象中的属性，`newValue` 和 `oldValue` 都是新值，因为它们是同一个对象。
 *
 * 若修改整个`ref`定义的对象，`newValue` 是新值， `oldValue` 是旧值，因为不是同一个对象了。
 */
watch(person, (newValue, oldValue) => {
  console.log('person发生了变化', newValue, oldValue);
}, {deep: true, immediate: true});

// 情况三：监视【reactive】定义的【对象类型】数据
/**
 * 数据
 */
const person1 = reactive<{ name: string, age: number }>({name: '张三', age: 18});

/**
 * 方法
 */
const changeName1 = (): void => {
  person1.name += '~';
};

const changeAge1 = (): void => {
  person1.age++;
};

const changePerson1 = (): void => {
  Object.assign(person1, {name: '李四', age: 20});
};

/**
 * 监听
 * 情况三：监视【reactive】定义的【对象类型】数据，且默认是开启深度监视的
 */
watch(person1, (newValue, oldValue) => {
  console.log('person1发生了变化', newValue, oldValue);
});
</script>

<style scoped lang="scss">
.person {
  background-color: skyblue;
  box-shadow: 0 0 10px;
  border-radius: 10px;
  padding: 20px;

  button {
    margin: 0 5px;
  }

  li {
    font-size: 20px;
  }
}
</style>
